//
//  ViewController.swift
//  ADKit
//
//  Created by Adoma on 10/22/2020.
//  Copyright (c) 2020 Adoma. All rights reserved.
//

import UIKit
import ADKit
import RxSwift
import Then
import DeviceKit
import SwiftyJSON
import SwiftyRSA

class ViewController: UIViewController {
    
    let disposebag = DisposeBag()
    
    let timer = ADTimer()
    
    let storage = SandboxStorage(name: "ADKitExample")
    
    let collectionView = UICollectionView { layout in
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view, typically from a nib.
//        UITextView().textLimit = 2
//         let input = UITextField()
//        input.textLimit = 2
    
        //397BC620-F9E0-47E2-B081-3EB69B69FAFF
//        let deviceid = Device.current.deviceid
//        print(deviceid)
        ADToast.Config.shared.yOffset = 0
        
//        let imageView = UIImageView()
//        view.addSubview(imageView)
//        imageView.snp.makeConstraints { make in
//            make.edges.equalToSuperview()
//        }
////        
//        DispatchQueue.main.after(time: 3) {
//            let data = UIImage.screenshot()?.compresse(to: 50_000)
//            imageView.image = UIImage(data: data!)
//        }
                
        let data = """
[
{
"name": "adoma",
"age": 19,
"money": 0
}
]
"""
//        
//        let observer = AnyObserver<Int> { event in
//            
//        }
//        let observable = Observable<Int>.create { observer in
//            
//            return Disposables.create {
//                
//            }
//        }
//        
//        observable.subscribe(observer)
//        
//        let btn = Person(age: 1)
//        let rx1 = btn.rx
//        let rx2 = btn.rx
//        print(rx1, rx2)
//        
//        let string = "adoma"
//        debugPrint(string.substring(from: 4))
        
        /**
         concatMap:
         它的作用是将每个源 Observable 发出的元素映射成一个新的 Observable，并且按照顺序将这些新 Observable 依次连接起来，形成一个新的序列。

         具体来说，concatMap 操作符会依次订阅源 Observable 发出的每个元素所对应的新 Observable，并且等待前一个 Observable 完成后才会订阅下一个 Observable。这样可以保证新 Observable 的订阅顺序与源 Observable 发出元素的顺序一致，且不会交错。

         因此，如果你有一个源 Observable 发出的元素需要按照顺序处理，并且每个元素都需要映射成一个新的 Observable 进行处理，那么可以考虑使用 concatMap 操作符。
         */
//        Observable.from(Array(0...10))
//            .concatMap({
//                print(Date(), "flatMap:\($0)")
//                return Observable.just($0).delay(.seconds(1), scheduler: MainScheduler.asyncInstance) })
//            .subscribe(onNext: { idx in
//                print(Date(), idx)
//            }, onError: { error in
//                print(error)
//            }, onCompleted: {
//                print("onCompleted")
//            }, onDisposed: {
//                print("onDisposed")
//            }).disposed(by: rx.disposeBag)
        
        
        print("hhhhhhhh")
        
//        PublicIPApi().request.subscribe(onNext: { data in
//            print(Date(), data.value)
//        }, onError: { error in
//            print(error)
//        }, onCompleted: {
//            print("onCompleted")
//        }, onDisposed: {
//            print("onDisposed")
//        }).disposed(by: rx.disposeBag)
//        
//        print("Hello, world!".sha1())
        
        /**
         JSON
         */
//        let json = data.toData
//        storage.set(data: json, for: "testJSON")
////        do {
////            try storage.set(data: json, for: "testJSON")
////        } catch {
////            print(error)
////        }
//        DispatchQueue.global().after(time: 3) {
//            let testJSON = self.storage.data(for: "testJSON")
//            adlog(json, testJSON, json == testJSON)
//        }
        
//        let publicData = NSDataAsset(name: "public")?.data
        let privateData = NSDataAsset(name: "private")?.data
        
        let publicData = try? Data(contentsOf: Bundle.main.path(forResource: "public_key", ofType: "pem")!.fileURL!)
//        let privateData = try? Data(contentsOf: Bundle.main.path(forResource: "private_key", ofType: "pem")!.fileURL!)

        let publicText = publicData?.toString
        let privateText = privateData?.toString
        
        print(publicText)
        print(privateText)
        
        let publicBase64 = remove(public: publicText!)
        let privateBase64 = remove(private: privateText!)
        
        print(publicBase64)
        print(privateBase64)

        let publicKey = createPublicKey(from: publicBase64)
        let privateKey = createPrivateKey(from: privateBase64)
        print(publicKey, privateKey)

        do {
            // 成功
//            let publicKey = try PublicKey(pemNamed: "public_key")
//            let privateKey = try PrivateKey(pemNamed: "private_key")
            
            // 成功
//            let publicKey = try PublicKey(pemEncoded: publicText!)
//            let privateKey = try PrivateKey(pemEncoded: privateText!)
            
            let publicKey = try PublicKey(base64Encoded: publicBase64)
            let privateKey = try PrivateKey(base64Encoded: privateBase64)
            
            print(publicKey, privateKey)

        } catch {
            print(error)
        }

    }
    
    func remove(public pemString: String) -> String {
        let base64Key = pemString
            .replacingOccurrences(of: "-----BEGIN PUBLIC KEY-----", with: "")
            .replacingOccurrences(of: "-----END PUBLIC KEY-----", with: "")
            .replacingOccurrences(of: "\n", with: "")
        return base64Key
    }
    
    func remove(private pemString: String) -> String {
        let base64Key = pemString
            .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "")
            .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "")
            .replacingOccurrences(of: "\n", with: "")
        return base64Key
    }
    
    func createPublicKey(from pemString: String) -> SecKey? {

        guard let keyData = Data(base64Encoded: pemString) else {
            print("公钥Base64解析失败")
            return nil
        }
        
        let options: [String: Any] = [
            kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
            kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
            kSecAttrKeySizeInBits as String: 2048
        ]
        
        var error: Unmanaged<CFError>?
        let key = SecKeyCreateWithData(keyData as CFData, options as CFDictionary, &error)
        if let err = error?.takeRetainedValue() {
            print("公钥导入错误: \(err)")
            return nil
        }
        return key
    }
    
    func createPrivateKey(from base64String: String) -> SecKey? {
  
        guard let keyData = Data(base64Encoded: base64String, options: [.ignoreUnknownCharacters]) else {
            print("私钥Base64解析失败")
            return nil
        }
        
        let sizeInBits = keyData.count * 8
        
        let options: [CFString: Any] = [
            kSecAttrKeyType: kSecAttrKeyTypeRSA,
            kSecAttrKeyClass: kSecAttrKeyClassPrivate,
            kSecAttrKeySizeInBits: NSNumber(value: sizeInBits),
            kSecReturnPersistentRef: true
        ]
        
        var error: Unmanaged<CFError>?
        let key = SecKeyCreateWithData(keyData as CFData, options as CFDictionary, &error)
        if let err = error?.takeRetainedValue() {
            print("私钥导入错误: \(err)")
            return nil
        }
        return key
    }
    
    
    struct PublicIPApi: RequestType {
        var host: String { "https://api.ipify.org" }
    }
    
    struct Person: Codable, ReactiveCompatible {
        var name: String?
        let age: Int
    }
    
    @IBAction func testWebView() {
        let scan = ADScanViewController()
        let text = TestADTextViewController()
        
        let test = TestEmptyViewController()
        
        var url = URL(string: "https://adoma.gitee.io")
        url = url?.append(query: ["name": "adoma", "age": "12"])
        let web = WebViewController(url: url!)
        try? ADRouter.routeWith(target: text)
//        ADRouter.routeWith(clsName: "TestWebViewController")
    }
    
    @IBAction func TestAuthorizeLocation() {
        print(#function)
        
        Authorize.shared.authorize(type: .location) {_ in 
            ADToast.show(msg: "TestAuthorize location completed!")
        }
        
    }
    
    @IBAction func TestAuthorizeCamera() {
        print(#function)
        
        Authorize.shared.authorize(type: .camera) {_ in 
            ADToast.show(msg: "TestAuthorize camera completed!")
        }
        
    }
    
    @IBAction func TestAuthorizePhotoLibrary() {
        print(#function)
        
        Authorize.shared.authorize(type: .photoLibrary) {_ in 
            ADToast.show(msg: "TestAuthorize photoLibrary completed!")
        }
        
    }
    
    @IBAction func TestAuthorizeContacts() {
        print(#function)
        
        Authorize.shared.authorize(type: .contacts) {_ in 
           try? ADRouter.routeWith(clsName: "TestContactsTableViewController")
        }
    }
    
    @IBAction func TestAuthorizeMicroPhone() {
        print(#function)
        
        Authorize.shared.authorize(type: .microPhone) {_ in 
            ADToast.show(msg: "TestAuthorize microPhone completed!")
        }
        
    }
    
    //MARK: 测试使用路由跳转控制器
    @IBAction func TestRoutAction() {
        print(#function)
        let block: ADPresentCompletedBlock = {
            print("adrouter is completed!")
        }
//        if let vc = ADRouter.routeWith(clsName: "TestRouterViewController", param: ["name": "adoma", "age": 22, ADRouterKey.isPresentTransAction: true, ADRouterKey.presentCompletedBlock: block, ADRouterKey.transActionNoAnimated: true]) {
//            print(vc)
//        }
        
        let map = ADRouter.RoutMap(scheme: "adkit", mapping: ["/routtest": "TestRouterViewController"])
        ADRouter.initialize(map: map)
        try? ADRouter.routeWith(urlString: "adkit://host/routtest?name=adoma&age=22")
    }
    
    @IBAction func testNetworkChanged(sender: UIButton) {
        print(#function)
        print(sender.ad_viewController)

//        if sender.isShowIndicator {
//            return
//        }
//        sender.showIndicator()
        
        ADToast.show(msg: "开始网络切换测试")
        NetworkListener.shared.start()
        
        NetworkListener.shared.status.subscribe(onNext: {
            ADLogger(category: "testNetworkChanged").debug("NetworkManager status changed !!", $0)
            switch $0 {
            case .wifi:
                ADToast.show(msg: "当前为Wifi连接")
            case.wwan:
                ADToast.show(msg: "当前为移动数据")
            case .unknown:
                ADToast.show(msg: "当前为不知道")
            case .none:
                ADToast.show(msg: "网络连接已断开")
            }
        }).disposed(by: disposebag)
        
        NetworkListener.shared.publicIP.subscribe(onNext: {
            ADLogger(category: "testNetworkChanged")
                .debug("NetworkManager publicIP changed !!", $0 ?? "no ip!!")
        }).disposed(by: disposebag)
    }
    
    var t = 0
    @IBAction func testRequest() {
        print(#function)
        ADToast.show(loading: "开始请求数据")
        t += 1
//        AdomaRequest.testJson(t: t).request.subscribe { json in
//            ADToast.show(msg: "请求完成")
//        } onFailure: { error in
//            ADToast.show(msg: "请求失败")
//        } onDisposed: {
//            
//        }.disposed(by: disposebag)

    }
    
    //MARK: 测试ADLOG
    @IBAction func testADLogAction() {
        ADLog.show()
    }
    
    @IBAction func testADAlertAction() {
        let alert = ADAlertViewController(title: "title", message: "message")
        alert.twoAction(callback: nil)
        alert.show()
    }
    
    @IBAction func testBundleManager() {
        print(#function)
        ADToast.show(msg: Bundle.main.description, hideDelay: 10)
    }
    
    @IBAction func testADActionSheet() {
        print(#function)
        let sheet = ADActionSheet()
        sheet.title = "退出后不会删除任何历史数据，下次登录依然可以使用本帐号。"
        let action = ADAction.init(title: "退出登录", style: .destructive) {
            print("退出登录成功")
        }
        sheet.cancelCallback = {
            print("cancelCallback")
        }
        sheet.add(action: action)
        sheet.show()
    }
    
    //MARK: 测试环境
    @IBAction func testEnv() {
        print(#function)
        let env = APPManager.shared.env
        ADToast.show(msg: "当前环境：\(env.type.rawValue)")
    }
    
    //MARK: 测试按钮转圈圈
    @IBAction func testIndicatorAction(_ sender: UIButton) {
        if sender.isShowIndicator {
            return
        }
        sender.showIndicator()
        ADToast.show(loading: "菊花转")
        
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
            ADToast.show(msg: "菊花转完了")
            sender.hideIndicator()
        }
    }
    
    // MARK: - 测试reusable
    @IBAction func testReuseable() {
        let target = TestReuseableCellController()
        try? ADRouter.routeWith(target: target)
    }
    
    // MARK: - 测试timer
    @IBAction func testTimerCD() {
        debugPrint("countDown start --\(Date())")
        timer.countDown(seconds: 61*60, increase: true) { time in
            debugPrint("countDown -- \(Date()) -- " , time)
        }
    }
    
    @IBAction func testTimerDelay() {
        debugPrint("delay start --\(Date())")
        timer.delay(seconds: 5, handler: {
            debugPrint("delay -- \(Date())")
        })
    }
    
    @IBAction func testTimerInterval() {
        debugPrint("interval start --\(Date())")
        timer.interval(seconds: 3) { time in
            debugPrint("interval -- \(Date()) -- " , time)
        }
    }
    
    @IBAction func testTimerCancel() {
        debugPrint("timer cancel --\(Date())")
        timer.invalidate()
    }
    
    @IBAction func testCollectionLayout() {
        let target = TestCollectionLayoutController()
        try? ADRouter.routeWith(target: target)
    }
}

extension ViewController {
    //MARK: 测试摇一摇调起log
    override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
        ADLog.show()
    }
}

